from copy import deepcopy
import pandas as pd
from jili.core.printlog import print
from research.pos import pos_frame
from jili.dataset import dataset
import datetime
from jili.data.db import tradecal
"""as 
self.pos  结构
self.pos obj bs ordersdetail
"""
class pos(pos_frame):
    def __init__(self, cash=100000000, fee=0.0008, targetnum=100,trademode="close",tardedelay=0, priceurl=r"G:\price",isdetail=False):
        super(pos,self).__init__(cash,isdetail)
        self.fee = fee
        self.targetnum = targetnum
        self.trademode=trademode
        self.tardedelay=tardedelay
        self.buysignals={}
        self.sellsignals={}
        self.posnum = 0
        self.tradeNo=0
        self.prebars = {}
        self.posrate_limit=1
        self.cashflow = [{"precash": cash, "balance": cash}]
        objs={"国证2000": {"obj": "399303", "is_selected": True, "aixs": 1}}
        self.set_benck_mark(objs)
        self.datatool_index=dataset(product="index",datatype="k1d",baseurl=priceurl,region="C",fqtype="bfq",source=None)
    def getposnum(self):
        rst = 0
        for obj, p in self.pos.items():
            for bs, v in p.items():
                #rst = rst + len(v)
                if v["qty"]>0:
                    rst=rst+1
        return rst
    def calc_avlfund(self):
        return self.fund["cash"]-self.holdcash
    def getbenckmark(self,obj,date_list):
        date_list.sort()
        startdate=date_list[0]
        enddate=date_list[-1]
        rst0=self.datatool_index.get_data(obj,startdate,enddate)
        return rst0
    def get_benck_net_add_time(self, index_obj):
        t = list(self.fund_his.keys())
        t.sort()
        rst = self.getbenckmark(index_obj, t)
        posrate_his = pd.Series(self.posrate_his)
        kd = pd.DataFrame(rst)
        kd["net"] = kd["CLOSE"].pct_change()
        kd["net"] = kd["net"] + 1
        kd['timekey'] = pd.to_datetime(kd['timekey'])
        kd.set_index('timekey', inplace=True)
        temp = kd["net"][posrate_his[posrate_his > 0].index]
        temp = temp.cumprod()
        temp = temp.reindex(t).fillna(method='ffill')
        temp = temp.fillna(1)
        temp = temp.to_list()
        return temp
    def signal_buy(self,obj,timekey,signal,p):
        if self.tardedelay==0:
            r0,r1= self.buy(timekey,obj,p["close"],msg=signal["buyinfo"])
            if not r0:
                signal["buyinfo"]=signal["buyinfo"]+"-pos:"+r1
        else:
            if obj not in self.buysignals.keys():
                self.buysignals[obj]={}
            runtk=tradecal.gettradeday(timekey,self.tradedelay)
            if runtk not in self.buysignals[obj].keys():
                self.buysignals[obj][runtk]=[]
            self.buysignals[obj][runtk].append(signal)
    def signal_sell(self,obj,timekey,signal,p):
        if self.tardedelay==0:
            self.sell(timekey,obj,p["close"],signal,msg=signal["sellinfo"])
        else:
            if obj not in self.sellsignals.keys():
                self.sellsignals[obj]={}
            runtk=tradecal.gettradeday(timekey,self.tradedelay)
            if runtk not in self.sellsignals[obj].keys():
                self.sellsignals[obj][runtk]=[]
            self.sellsignals[obj][runtk].append(signal)
    def onbar(self,b):
        super().onbar(b)
        obj=b["obj"]
        tk=b["timekey"]
        if obj in self.buysignals.keys():
            if tk in self.buysignals[obj].keys():
                for i in self.buysignals[obj][tk]:
                    r0, r1 = self.buy(tk, obj, b[self.trademode], msg=i["buyinfo"])
                    if not r0:
                        i["buyinfo"] = i["buyinfo"] + "-pos:" + r1
                del self.buysignals[obj][tk]
        if obj in self.sellsignals.keys():
            if tk in self.sellsignals[obj].keys():
                for i in self.sellsignals[obj][tk]:
                    r0, r1 = self.buy(tk, obj, b[self.trademode], msg=i["buyinfo"])
                    if not r0:
                        i["buyinfo"] = i["buyinfo"] + "-pos:" + r1
                del self.sellsignals[obj][tk]
    def havelongpos(self, obj):
        rst = False
        if obj in self.pos.keys():
            if "buy" in self.pos[obj].keys():
                if len(self.pos[obj]["buy"]) > 0:
                    rst = True
        return rst
    def buy(self, timekey, obj, price,qty=None,posrate=None,amount=None,msg=""):
        self.posnum = self.getposnum()  #按股票计算持仓数量
        # self.posnum = self.getposordersnum()  #按开仓订单计算持仓数量
        fee=price*self.fee
        price = price * (1 + self.fee)
        if (self.targetnum == self.posnum):# and (obj not in self.pos.keys()):
            # print(timekey, obj, price, "已经达到持有份数，现金不足", self.posnum)
            return False,"已经达到持有份数,现金不足"
        else:
            cash=self.calc_avlfund()
            if amount   is None:
                if posrate is None:
                    if qty is None:
                        if cash < 100:
                            print(timekey, obj, price, "现金不足", cash)
                            return False, "现金不足"
                        else:
                            amont0 = cash/(self.targetnum-self.posnum)
                    else:
                        amont0=qty*price
                        if amont0>cash:
                            print(timekey, obj, price, "现金不足", cash,amont0)
                            return False, "现金不足"
                else:
                    if cash < 100:
                        print(timekey, obj, price, "现金不足", cash)
                        return False,"现金不足"
                    else:
                        if self.targetnum > self.posnum:
                            amont0=cash/(self.targetnum-self.posnum+self.targetnum*(1-self.posrate_limit)/self.posrate_limit)
                        else:
                            amont0 = self.posrate_limit * cash / self.targetnum
            else:
                if cash < amount:
                    amont0 = cash
                else:
                    amont0 = amount
            # margin=amont0
            # amount1=amont0
            # amount2=amont0
            # fee_tick=0
            if amont0 > 100:
                self.tradeNo = self.tradeNo + 1
                balance = {"precash": cash, "date": timekey, "tradeNo": self.tradeNo}
                order=self.create_order()
                order0={"obj":obj,"bs":"buy","buyprice":price,"buyamount":amont0,"qty":amont0/price,"opentimekey":timekey,"buymsg":msg,
                       "buy_precash":cash,"targetnum":self.targetnum,"posnum":self.posnum,"posrate":self.posrate_limit}
                order.update(order0)
                order["fee"]=order["qty"]*fee
                # print("新增买入", timekey, obj, price, amount)
                p=self.create_pos()
                p0={"obj":obj,"bs":"buy","costprice":price,"highprice":price,"costamount":amont0,"qty":amont0/price,"close_pl":0,"closevalue":0,"openvalue":amont0,"detail":[order]}
                p.update(p0)
                if obj not in self.pos.keys():
                    self.pos[obj] = {}
                if "buy" not in self.pos[obj].keys():
                    self.pos[obj]["buy"] = []
                self.pos[obj]["buy"].append(p)

                self.cash2pos(amont0)
                balance["amount"] = amont0
                balance["balance"] = cash
                balance.update({"targetnum": self.targetnum, "posnum": self.getposnum(), "posrate": self.posrate_limit})
                balance["msg"] = str(order)
                if self.isdetail:
                    self.cashflow.append(balance)
                return True,str(self.tradeNo)
            else:
                print("验资失败，资金不足100元")
                return False,"现金不足"
    def sell(self, timekey, obj, price,pos,msg=""):
        i = pos
        self.tradeNo = self.tradeNo + 1
        order0 = deepcopy(i)
        order = {}
        order["sellprice"] = price
        order["closetimekey"] = timekey
        fee= i["qty"] * price * self.fee
        order["pl"] = i["qty"] * (price * (1 - self.fee) - i["buyprice"])
        order["sellamount"] = i["qty"] * price * (1 - self.fee)
        order["plr"]=order["pl"]/order0["buyamount"]
        order["fee"]=fee+order0["fee"]
        order["sellmsg"] = msg
        precash = self.calc_avlfund()
        #self.check_calcpl(order["pl"], order["sellamount"])
        cash=self.pos2cash(order["sellamount"])
        order0.update(order)
        self.orders_his.append(order0)
        balance = {"precash": precash, "date": timekey, "tradeNo": self.tradeNo}
        balance["amount"] = -order["sellamount"]
        balance["balance"] = cash
        balance.update(
            {"targetnum": self.targetnum, "posnum": self.getposnum() - 1, "posrate": self.posrate_limit})
        balance["msg"] = ""#str(order)
        if self.isdetail:
            self.cashflow.append(balance)
        return True, ""
    def calc_fund(self):
        value=0
        for obj,v in self.pos.items():
            for bs,orders in v.items():
                for p in orders:
                    if p["qty"] > 0:
                        if obj not in self.bar_pool.keys():
                            key=list(self.bar_pool.keys())[0]
                            date=self.bar_pool[key]["timekey"]
                            print("退市票，ondayend卖出", date, obj, self.bar_pool[obj]["close"])
                            self.sell(timekey=date, obj=obj, price=self.bar_pool[obj]["close"], msg="检查到退市")
                            value = value + self.bar_pool[obj]["close"]*p["qty"]
                        else:
                            t = self.bar_pool[obj]
                            price = t["close"] * (1 - self.fee)
                            if "close_pl" not in p.keys():
                                p["close_pl"] = 0
                                p["closevalue"] = 0
                            p["value"] = price * p["qty"]
                            p["pl"] = p["value"] - p["costamount"]
                            value = value + p["value"]
                            if price > p["highprice"]:
                                p["highprice"] = price
        self.fund["margin"]=value
        self.fund["balance"]=self.fund["margin"]+self.fund["cash"]
        return self.fund
    def ondayend(self, date, data={}):#默认第一天净值处理
        d = datetime.datetime(date.year, date.month, date.day)
        if d not in self.fund_his.keys():
            if not self.fund_his:
                t1 = datetime.datetime(date.year, date.month, date.day) - datetime.timedelta(days=1)
                self.fund_his[t1] = self.cash0
                self.posrate_his[t1] = 0
                self.return_his[t1]=0
            prebalance = self.fund["prebalance"]
            self.calc_fund()
            issavepos = False
            for obj, v in self.pos.items():
                for bs, orders in v.items():
                    for p in orders:
                        if p["qty"] > 0:
                            issavepos = True
            if issavepos and self.isdetail:
                self.pos_his[date] = deepcopy(self.pos)
            cashin=self.fund["cashin"]
            fund0=self.fund["balance"]
            if self.maxfund < fund0:
                self.maxfund = fund0
            self.fund_his[date] = fund0
            self.curr_return = (fund0 - self.cash0- self.cashin_total) / (self.cash0+ self.cashin_total)
            self.return_byday = (fund0 - prebalance-cashin) / (prebalance + cashin)
            self.return_his[date] = self.return_byday
            self.curr_posrate = (fund0 - self.fund["cash"]) / fund0
            self.posrate_his[date] = self.curr_posrate
            self.fund["prebalance"]=fund0
            self.fund["cashin"]=0
            print("日终计算", d, date, self.curr_posrate, fund0, self.curr_return, self.return_byday)
            # if data:
            #     self.prebars=data
            # else:
            #     self.prebars=deepcopy(self.bar_pool)


pos_stock_byunit=pos